/*
 * Copyright 2012 Finbudget.com
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package finbudgettable.client.ui.grid.cell.date.filter;

import finbudget.client.ui.table.Record;
import finbudgettable.client.ui.grid.cell.date.DateFilterPanel;
import finbudgettable.client.ui.grid.filter.FieldFilter;
import finbudgettable.client.ui.grid.filter.Filter;
import finbudgettable.client.ui.grid.filter.ValueAdapter;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * Filter package with simple data type templating
 */
public class Filters {

    public static final String EQUAL_OPERATION = "=";
    public static final String NOT_EQUAL_OPERATION = "<>";
    public static final String GREATER_OPERATION = ">";
    public static final String GREATER_OR_EQUAL_OPERATION = ">=";
    public static final String LESS_OPERATION = "<";
    public static final String LESS_OR_EQUAL_OPERATION = "<=";

    interface FilterFactory {
        String getOp();
        Filter create(DateFilterPanel filterPanel);
    }

    abstract static class AbstractDateFilterFactory implements FilterFactory {

        private final String op;

        protected AbstractDateFilterFactory(String op) {
            this.op = op;
        }

        @Override
        public String getOp() {
            return op;
        }
    }

    public interface FilterPresenter {
        void show(DateFilterPanel filterPanel, FieldFilter<Date> filter);
    }

    protected final Map<String, FilterFactory> operations = new HashMap<String, FilterFactory>();
    protected final Map<Class<?>, FilterPresenter> presenters = new HashMap<Class<?>, FilterPresenter>();

    public Filters(final ValueAdapter<Record, Date> valueAdapter) {
        initEqualFilter(valueAdapter);
        initNotEqualFilter(valueAdapter);
        initGreaterFilter(valueAdapter);
        initGreaterOrEqualFilter(valueAdapter);
        initLessFilter(valueAdapter);
        initLessOrEqualFilter(valueAdapter);
    }

    private void initEqualFilter(final ValueAdapter<Record, Date> valueAdapter) {
        final FilterFactory factory = new AbstractDateFilterFactory(EQUAL_OPERATION) {
            @Override
            public Filter create(DateFilterPanel filterPanel) {
                return new EqualDateFilter(valueAdapter, filterPanel.getValue());
            }
        };
        FilterPresenter presenter = new FilterPresenter() {
            @Override
            public void show(DateFilterPanel filterPanel, FieldFilter<Date> filter) {
                if (filterPanel.setOperationByName(factory.getOp())) {
                    filterPanel.setValue(filter.getValue());
                }
            }
        };
        operations.put(factory.getOp(), factory);
        presenters.put(EqualDateFilter.class, presenter);
    }

    private void initNotEqualFilter(final ValueAdapter<Record, Date> valueAdapter) {
        final FilterFactory factory = new AbstractDateFilterFactory(NOT_EQUAL_OPERATION) {
            @Override
            public Filter create(DateFilterPanel filterPanel) {
                return new NotEqualDateFilter(valueAdapter, filterPanel.getValue());
            }
        };
        FilterPresenter presenter = new FilterPresenter() {
            @Override
            public void show(DateFilterPanel filterPanel, FieldFilter<Date> filter) {
                if (filterPanel.setOperationByName(factory.getOp())) {
                    filterPanel.setValue(filter.getValue());
                }
            }
        };
        operations.put(factory.getOp(), factory);
        presenters.put(NotEqualDateFilter.class, presenter);
    }

    private void initGreaterFilter(final ValueAdapter<Record, Date> valueAdapter) {
        final FilterFactory factory = new AbstractDateFilterFactory(GREATER_OPERATION) {
            @Override
            public Filter create(DateFilterPanel filterPanel) {
                return new GreaterDateFilter(valueAdapter, filterPanel.getValue());
            }
        };
        FilterPresenter presenter = new FilterPresenter() {
            @Override
            public void show(DateFilterPanel filterPanel, FieldFilter<Date> filter) {
                if (filterPanel.setOperationByName(factory.getOp())) {
                    filterPanel.setValue(filter.getValue());
                }
            }
        };
        operations.put(factory.getOp(), factory);
        presenters.put(GreaterDateFilter.class, presenter);
    }

    private void initGreaterOrEqualFilter(final ValueAdapter<Record, Date> valueAdapter) {
        final FilterFactory factory = new AbstractDateFilterFactory(GREATER_OR_EQUAL_OPERATION) {
            @Override
            public Filter create(DateFilterPanel filterPanel) {
                return new GreaterOrEqualDateFilter(valueAdapter, filterPanel.getValue());
            }
        };
        FilterPresenter presenter = new FilterPresenter() {
            @Override
            public void show(DateFilterPanel filterPanel, FieldFilter<Date> filter) {
                if (filterPanel.setOperationByName(factory.getOp())) {
                    filterPanel.setValue(filter.getValue());
                }
            }
        };
        operations.put(factory.getOp(), factory);
        presenters.put(GreaterOrEqualDateFilter.class, presenter);
    }

    private void initLessFilter(final ValueAdapter<Record, Date> valueAdapter) {
        final FilterFactory factory = new AbstractDateFilterFactory(LESS_OPERATION) {
            @Override
            public Filter create(DateFilterPanel filterPanel) {
                return new LessDateFilter(valueAdapter, filterPanel.getValue());
            }
        };
        FilterPresenter presenter = new FilterPresenter() {
            @Override
            public void show(DateFilterPanel filterPanel, FieldFilter<Date> filter) {
                if (filterPanel.setOperationByName(factory.getOp())) {
                    filterPanel.setValue(filter.getValue());
                }
            }
        };
        operations.put(factory.getOp(), factory);
        presenters.put(LessDateFilter.class, presenter);
    }

    private void initLessOrEqualFilter(final ValueAdapter<Record, Date> valueAdapter) {
        final FilterFactory factory = new AbstractDateFilterFactory(LESS_OR_EQUAL_OPERATION) {
            @Override
            public Filter create(DateFilterPanel filterPanel) {
                return new LessOrEqualDateFilter(valueAdapter, filterPanel.getValue());
            }
        };
        FilterPresenter presenter = new FilterPresenter() {
            @Override
            public void show(DateFilterPanel filterPanel, FieldFilter<Date> filter) {
                if (filterPanel.setOperationByName(factory.getOp())) {
                    filterPanel.setValue(filter.getValue());
                }
            }
        };
        operations.put(factory.getOp(), factory);
        presenters.put(LessOrEqualDateFilter.class, presenter);
    }


    public Filter createFilter(DateFilterPanel filterPanel, String op) {
        FilterFactory factory = operations.get(op);
        return factory.create(filterPanel);
    }


    public FilterPresenter getPresenter(Class<?> clazz) {
        return presenters.get(clazz);
    }

    public Map<String, FilterFactory> getOperations() {
        return operations;
    }
}
